const cacheNameFunction = <T extends (str: string) => string>(fn: T): T => {
  const cache: Record<string, string> = Object.create(null)
  return ((str: string) => {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }) as T
}

function _toCamelCase(str?: string | null): string | null {
  if (str == null) return null;
  let res = ''
  for (let i = 0; i < str.length; i++) {
    const c = str[i]
    if (c === '-' || c === '_') {
      if (i >= str.length - 1) break
      res += str[++i].toUpperCase()
    } else {
      res += c
    }
  }
  return res
}


function _toUnderscoreCase(str?: string | null): string | null {
  if (str == null) return null
  let res = ''
  for (const c of str) {
    if (c >= 'A' && c <= 'Z') {
      res += '_' + c.toLowerCase()
    } else {
      res += c
    }
  }
  return res
}

/**
 * toCamelCase('search-form') => searchForm
 */
export const toCamelCase: (str?: string | null) => string = cacheNameFunction(_toCamelCase)

/**
 * toUnderscoreCase('searchForm') => search-form
 */
export const toUnderscoreCase: (str?: string | null) => string = cacheNameFunction(_toUnderscoreCase)
